﻿using GN.Pay.TradeChannel.WeiXin.Response;
using GN.Pay.Utils.Net.Http;
using GN.Pay.Utils.Security;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;

namespace GN.Pay.TradeChannel.WeiXin.Request
{
    /// <summary>
    /// 退款请求
    /// </summary>
    [Serializable]
    public class RefundRequest : AServiceRequest
    {
        public RefundRequest(IRefundApplyInfo apply,
             WeiXinConfigure config)
        {
            AppId = config.ConfigureInfo.AppId;
            Mch_Id = config.ConfigureInfo.AccountId;
            Device_Info = "";
            //if (!string.IsNullOrWhiteSpace(apply.OrderNo))
            //{
            //    Transaction_Id = "";
            //    Out_Trade_No = apply.OrderNo;
            //}
            //else
            //{
            //    Transaction_Id = apply.TradeNo;
            //    Out_Trade_No = "";
            //}

            if (!string.IsNullOrWhiteSpace(apply.TradeNo))
            {
                Transaction_Id = apply.TradeNo;
                Out_Trade_No = "";
            }
            else
            {
                Transaction_Id = "";
                Out_Trade_No = apply.OrderNo;
            }
            Out_Refund_No = apply.RefundNo;
            Total_Fee = GetMoneyForCent(apply.OrderMoney);
            Refund_Fee = GetMoneyForCent(apply.ApplyMoney);
            Op_User_Id = config.ConfigureInfo.AccountId;
        }

        /// <summary>
        /// 微信分配的公众账号ID（企业号corpid即为此appId）
        /// </summary>
        [Required(ErrorMessage = "微信分配的公众账号ID（企业号corpid即为此appId） 不能这空")]
        public string AppId { get; set; }

        /// <summary>
        /// 微信支付分配的商户号
        /// </summary>
        [Required(ErrorMessage = "Mch_Id(微信支付分配的商户号)不能这空")]
        public string Mch_Id { get; set; }

        /// <summary>
        /// 终端设备号
        /// </summary>
        public string Device_Info { get; set; }

        /// <summary>
        /// 微信生成的订单号，在支付通知中有返回(与 Out_Trade_No 至少一个不能为空)
        /// </summary>
        public string Transaction_Id { get; set; }

        /// <summary>
        /// 商户传给微信的订单号(与 Transaction_Id 至少一个不能为空)
        /// </summary>
        public string Out_Trade_No { get; set; }

        /// <summary>
        /// 商户退款单号
        /// </summary>
        [Required(ErrorMessage = "Out_Refund_No(商户退款单号)不能这空")]
        public string Out_Refund_No { get; set; }

        /// <summary>
        /// 订单总金额，单位为分，只能为整数
        /// </summary>
        [Range(1, int.MaxValue, ErrorMessage = "订单总金额不能低于1分钱")]
        public long Total_Fee { get; set; }

        /// <summary>
        /// 退款总金额，单位为分，只能为整数
        /// </summary>
        [Range(1, int.MaxValue, ErrorMessage = "退款金额不能低于1分钱")]
        public long Refund_Fee { get; set; }

        /// <summary>
        /// 
        /// </summary>
        [Required(ErrorMessage = "Op_User_Id(操作用户，一般为商户号)不能这空")]
        public string Op_User_Id { get; set; }

        protected override IEnumerable<ValidationResult> ServiceValidate(ValidationContext validationContext)
        {
            if (string.IsNullOrWhiteSpace(Transaction_Id) && string.IsNullOrWhiteSpace(Out_Trade_No))
            {
                yield return new ValidationResult("订单号与微信交易号不能同时为空");
            }
            yield return null;
        }

        private const string REFUND_URL = "https://api.mch.weixin.qq.com/secapi/pay/refund";

        /// <summary>
        /// 生成
        /// </summary>
        /// <param name="channel">通道</param>
        /// <param name="config">配置</param>
        /// <returns></returns>
        public ITradeRefundApplyResult Build(ITradeChannel channel, WeiXinConfigure config)
        {
            Validate(channel);
            string requestXml = BuildSignXmlParam(channel, config, "sign");            
            byte[] cert = config.ConfigureInfo.RefundCretRaw();
            if (cert == null)
            {
                channel.ThrowChannelValidationException("未配置微信双向证书");
            }
            HttpClient client = new HttpClient();
            var certificate = RsaUtils.CreateCertificate(cert, config.ConfigureInfo.AccountId);
            client.Certificates.Add(certificate);
            var result = client.PostString(new Uri(REFUND_URL), requestXml);
            RefundResponse res = new RefundResponse(result);
            if (res.IsFullSuccess())
            {
                if (!res.SignVerify(config))
                {
                    channel.ThrowChannelValidationException("退款验签失败");
                }
            }
            return res.ToResult(channel);
        }
    }
}
